package com.zlc.workflow.core.instance.cmd;

import com.zlc.common.util.JsonHelper;
import com.zlc.common.util.SpringContextUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 命令模式
 *
 * @author zl
 */
@Slf4j
public abstract class AbstractCmd<T>{

    /**
     * 获取当前命令对象的所有带 @Autowired注解的属性，然后从spring上下文中获取到注入进去
     */
    public AbstractCmd(Object params){
        String cmdName = this.getClass().getSimpleName();
        log.info("开始执行命令："+cmdName);
        if(log.isDebugEnabled()){
            log.debug("执行命令["+cmdName+"]参数："+ JsonHelper.toJson(params));
        }
        List<Field> fields = getFields(getClass(),new ArrayList<>());
        if(!ObjectUtils.isEmpty(fields)){
            for(Field field : fields){
                //springbean
                Autowired autowired = field.getAnnotation(Autowired.class);
                Resource resource = field.getAnnotation(Resource.class);
                if(autowired != null || resource!=null){
                    Class<?> bean = field.getType();
                    Object springBean = SpringContextUtils.getBean(bean);
                    Assert.isTrue(!ObjectUtils.isEmpty(springBean),"bean: "+bean.getName()+" not found in spring application!");
                    try {
                        field.setAccessible(true);
                        field.set(this,springBean);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                        throw new RuntimeException(e.getMessage(),e);
                    }
                }

            }

        }
    }


    private List<Field> getFields(Class copy, List<Field> fields){
        fields.addAll(Arrays.asList(copy.getDeclaredFields()));
        if(copy.getSuperclass() != Object.class){
            Class superCopy = copy.getSuperclass();
            getFields(superCopy,fields);
            return fields;
        }else{
            return fields;
        }
    }


    private List<Method> getMethods(Class bean, List<Method> methods){
        methods.addAll(Arrays.asList(bean.getDeclaredMethods()));
        if(bean.getSuperclass() != Object.class){
            Class superCopy = bean.getSuperclass();
            getMethods(superCopy,methods);
            return methods;
        }else{
            return methods;
        }
    }


    public abstract T  execute();
}